/**
 *
 */
package com.angel.common.providers.base;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.angel.common.providers.annotations.Identificator;
import com.angel.common.providers.exceptions.ObjectNotSupportIdentifierNameException;
import com.angel.common.providers.managers.ObjectProviderNameAnnotationManager;
import com.angel.dao.generic.interfaces.GenericDAO;

/**
 * @author William
 *
 */
public class ObjectProvider<T extends Object> implements Serializable{

	private static final long serialVersionUID = -7316755382389671384L;
	private ObjectProviderNameAnnotationManager manager = new ObjectProviderNameAnnotationManager();
	private Class<T> objectProviderClass = null;
	private Map<String, T> objects = new HashMap<String, T>();
	private GenericDAO<T, Serializable> genericDAO;

	public ObjectProvider(GenericDAO<T, Serializable> genericDAO, Class<T> classObject){
		this(classObject);
		this.genericDAO = genericDAO;
	}

	public ObjectProvider(Class<T> classObject){
		super();
		this.objectProviderClass = classObject;
	}

	/**
	 * @return the genericDAO
	 */
	public GenericDAO<T, Serializable> getGenericDAO() {
		return genericDAO;
	}

	/**
	 * @param genericDAO the genericDAO to set
	 */
	public void setGenericDAO(GenericDAO<T, Serializable> genericDAO) {
		this.genericDAO = genericDAO;
	}

	public boolean containsObject(String name){
		return this.objects.containsKey(name);
	}

	public boolean overridesObject(String name, T value){
		boolean overrided= false;
		if(this.containsObject(name)){
			overrided = this.objects.put(name, value) != null;
		}
		return overrided;
	}

	public boolean addObject(String name, T object){
		boolean added = false;
		if(!this.containsObject(name)){
			added = this.objects.put(name, object) == null;
		}
		return added;
	}

	public boolean addObject(T object){
		boolean added = false;
		if(manager.canIdentifyObjectByName(this.getObjectProviderClass())){
			String name = manager.getIdentifierNameFor(object);
			added = this.addObject(name, object);
		} else {
			throw new ObjectNotSupportIdentifierNameException("Objects' class [" );//+ this.getObjectProviderClass().getSimpleName() + "] not support identifier object name with [" + ObjectProviderName.class.getSimpleName() + "] annotation.");
		}
		return added;
	}

	public boolean removeObject(String name){
		return this.objects.remove(name) != null;
	}

	public T providesObject(String name){
		return this.objects.get(name);
	}

	public void clear(){
		this.objects.clear();
	}

	public int reinitialize(){
		this.clear();
		return this.initialize();
	}

	public int initialize(){
		int quantityInitialized = 0;
		if(this.genericDAO != null){
			Collection<T> initializeObjects = this.genericDAO.findAll();
			if(manager.canIdentifyObjectByName(this.getObjectProviderClass())){
				for(T t: initializeObjects){
					String name = manager.getIdentifierNameFor(t);
					if(this.addObject(name, t)){
						quantityInitialized++;
					}
				}
			} else {
				throw new ObjectNotSupportIdentifierNameException("Objects' instances [" + this.getObjectProviderClass() + "] don't support identifier object name with [" + Identificator.class.getSimpleName() + "] annotation.");
			}
		}
		return quantityInitialized;
	}

	public int initialize(Map<String, T> mapObjects){
		int quantityInitialized = 0;
		Set<String> keySet = mapObjects.keySet();
		for(String key: keySet){
			T object = mapObjects.get(key);
			if(this.addObject(key, object)){
				quantityInitialized++;
			}
		}
		return quantityInitialized;
	}

	/**
	 * @return the objectProviderClass
	 */
	protected Class<?> getObjectProviderClass() {
		return objectProviderClass;
	}

	public int quantityObject(){
		return this.objects.size();
	}

	protected Collection<T> getValues(){
		return this.objects.values();
	}

}
